package main;

import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.text.BadLocationException;

import constants.General_Constants;

import access.*;

@SuppressWarnings("serial")
public class Console extends JPanel implements KeyListener{
	JTextArea TextAreaPanel = new JTextArea();
	JTextField TextFieldPanel = new JTextField();
	JScrollPane ScrollBox = null;
	
	final private int maxTextLength = 2000;
	final private int maxRemainingText = 500;
	/**
	 * @param maxLogBytes
	 * <pre>Each log file can only be one megabyte long before
	 * a new log file is generated.
	 */
	final private int maxLogBytes = 1024 * 1024;
	
	private boolean loggingToggle = false;
	
	final private String logFileBase = "\\logs\\";
	//final private String currentDir = new File("").getAbsolutePath();
	
	FileOutputStream outLog;
	
	final private DateFormat dateFormat = new SimpleDateFormat("yyyy-dd-MM HH.mm");
	final private DateFormat dateFormatBackUp = new SimpleDateFormat("yyyy-dd-MM HH.mm.ss");
	final private Date date = new Date();
	
	private Request requestSent = new Request();
	
	private Vault Security = new Vault();
	
	//private User inControl = new User();
	
	/**
	 * <pre>Base constructor</pre>
	 * @param a_D
	 */
	public Console() {
		super(new BorderLayout());
		setupLayout();
		loggingToggle = true;
		if(new File(logFileBase).exists() != true) {
			new File(General_Constants.currentDir + logFileBase).mkdir();
		}
		openLogFile();
	}
	
	/**
	 * <pre>Base constructor plus the ability to control the logging.</pre>
	 * @param a_D
	 * @param toggleState
	 */
	public Console(boolean toggleState) {
		super(new BorderLayout());
		setupLayout();
		loggingToggle = toggleState;
		if(new File(logFileBase).exists() != true) {
			new File(General_Constants.currentDir + logFileBase).mkdir();
		}
		if(loggingToggle) {
			openLogFile();
		}
	}

	final private void setupLayout() {
		TextAreaPanel.setEditable(false);
		TextAreaPanel.setRows(5);
		TextAreaPanel.setColumns(10);
		
		TextFieldPanel.setEditable(true);
		TextFieldPanel.setColumns(20);
		TextFieldPanel.addKeyListener(this);
		
		ScrollBox = new JScrollPane(TextAreaPanel);
		ScrollBox.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		ScrollBox.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
		ScrollBox.setAutoscrolls(true);
		
		add(ScrollBox, BorderLayout.CENTER);
        add(TextFieldPanel, BorderLayout.SOUTH);
	}
	
	public void submit() throws IOException {
		if(loggingToggle)
			sendToLog("User: " + TextFieldPanel.getText() + "\n");
		TextAreaPanel.insert(TextFieldPanel.getText() + "\n", 0);
		
		//Check if it is a command, if its not this function breaks out
		handleCommand(TextFieldPanel.getText());
		
		//Return to top of text area
		TextAreaPanel.select(0, 0);
		
		//Clear text field
		TextFieldPanel.selectAll();
		TextFieldPanel.replaceSelection("");
		
		clearExcess();
	}

	public void submit(String a_Text) throws IOException {
		if(loggingToggle)
			sendToLog("Program: " + a_Text + "\n");
		TextAreaPanel.insert(a_Text + "\n",0);
		
		//Check if it is a command, if its not this function breaks out
		handleCommand(a_Text);
		
		//Return to top of text area
		TextAreaPanel.select(0, 0);
		clearExcess();
	}
	
	public void submitEntryReq(Request_Types a_Req) {
		sendRequest(a_Req);
		submitEntryReq(requestSent);
	}
	
	public void submitEntryReq(Request a_Req) {
		if(loggingToggle)
			sendEntryReqToLog("Program Requested: " + a_Req.getInfo() + "\n");
		TextAreaPanel.insert(a_Req.getInfo() + " \n", 0);
		TextAreaPanel.select(0, 0);
		clearExcess();
		try {
			while(handleRequest() != true){}
		} catch (IOException e) { e.printStackTrace(); }
	}
	
	public void submitEntry() {
		if(loggingToggle)
			sendEntryToLog("User Entered: " + TextFieldPanel.getText() + "\n");
		try {
			if(requestSent.myType != Request_Types.PASSWORD)
				TextAreaPanel.insert(" " + TextFieldPanel.getText(), TextAreaPanel.getLineEndOffset(0)-1);
		} catch (BadLocationException e) { e.printStackTrace(); }
		
		try {
			handleEntry(TextFieldPanel.getText());
		} catch (IOException e) { e.printStackTrace(); }
		
		TextAreaPanel.select(0, 0);
		TextFieldPanel.selectAll();
		TextFieldPanel.replaceSelection("");
		clearExcess();
	}
	
	private void openLogFile() {
		try {
			String newFileName = General_Constants.currentDir + logFileBase +  dateFormat.format(date) + ".netlog";
			String newBackUpFileName = General_Constants.currentDir + logFileBase +  dateFormatBackUp.format(date) + ".netlog";
			File F = new File(newFileName);
			if(F.exists())
				outLog = new FileOutputStream(newBackUpFileName);
			else
				outLog = new FileOutputStream(newFileName);
			F = null;
		} catch (FileNotFoundException e) { e.printStackTrace(); }
	}
	
	private void manageLogFile() {
		try {
			outLog.close();
		} catch (IOException e) { e.printStackTrace(); }
		outLog = null;
		openLogFile();
	}
	
	public void sendToLog(String a_Log) {
		if(a_Log.length() > 0) {
			try {
				outLog.write((a_Log + "\n").getBytes());
				if(outLog.getChannel().position() >= maxLogBytes) { 
					manageLogFile();
				}
			} catch (IOException e) { e.printStackTrace(); }
		}
	}
	
	public void sendEntryReqToLog(String a_Log) {
		if(a_Log.length() > 0) {
			try {
				outLog.write((a_Log).getBytes());
				if(outLog.getChannel().position() >= maxLogBytes) { 
					manageLogFile();
				}
			} catch (IOException e) { e.printStackTrace(); }
		}
	}
	
	public void sendEntryToLog(String a_Log) {
		if(a_Log.length() > 0) {
			try {
				outLog.write((" " + a_Log + "\n").getBytes());
				if(outLog.getChannel().position() >= maxLogBytes) { 
					manageLogFile();
				}
			} catch (IOException e) { e.printStackTrace(); }
		}
	}
	
	public void clearExcess() {
		if(TextAreaPanel.getDocument().getLength() > maxTextLength) {
			try {
				TextAreaPanel.getDocument().remove(maxRemainingText, TextAreaPanel.getDocument().getLength() - maxRemainingText);
			} catch (BadLocationException e) { e.printStackTrace(); }
		}
	}
	
	public void sendRequest(Request_Types a_Request) {
		requestSent.myType = a_Request;
	}
	
	private void clearRequest() {
		requestSent.myType = Request_Types.NO_REQ;
	}
	
	public boolean handleRequest() throws IOException {
		switch(requestSent.myType) {
		case NO_REQ: return true;
		case LOGIN:
			clearRequest();
			if(!Security.isLoggedin()) {
				Security.logout();
				sendRequest(Request_Types.USERNAME);
			}
			return false;
		case LOGOUT:
			return true;
		case SU:
			Security.logout();
			sendRequest(Request_Types.LOGIN);
			return false;
		case USERNAME:
			submit(requestSent.getInfo());
			return true;
		case PASSWORD:
			//submitEntryReq(requestSent);
			return true;
		default: return true;
		}
	}

	public void handleEntry(String a_Entry) throws IOException {
		switch(requestSent.myType) {
		case NO_REQ: break;
		case LOGIN: break;
		case USERNAME:
			if(Security.UserExists(a_Entry)) {
				Security.holdUsername(a_Entry);
				sendRequest(Request_Types.PASSWORD);
			}
			else {
				sendRequest(Request_Types.LOGIN);
				submit("User does not Exist");
			}
			submitEntryReq(requestSent);
			break;
		case PASSWORD:
			Security.holdPassword(a_Entry);
			if(Security.login() != true) {
				submit("Login failed");
				sendRequest(Request_Types.LOGIN);
				submitEntryReq(requestSent);
			}
			else {
				submit("Login Successful");
			}
			sendRequest(Request_Types.NO_REQ);
			break;
		case LOGOUT:
			if(Security.isLoggedin())
				Security.logout();
			break;
		}
	}

	private void handleCommand(String text) throws IOException {
		StringReader sr = new StringReader(text);
		char[] buffer = null;
		
		switch(sr.read()) {
		case '+':
			buffer = new char[16];
			sr.read(buffer);
			commandList.execute(this,String.valueOf(buffer).trim());
			break;
		}
	}
	
	public boolean ReqEntry() {
		if(requestSent.equals(null))
			return false;
		else if(requestSent.myType == Request_Types.NO_REQ || requestSent.myType == null)
			return false;
		return true;
	}

	
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode() == KeyEvent.VK_ENTER) {
			if(this.ReqEntry())
				this.submitEntry();
			else {
				try {
					this.submit();
				} catch (IOException e1) { e1.printStackTrace(); }
			}
		}
	}
	public void keyReleased(KeyEvent e) {}
	public void keyTyped(KeyEvent e) {}
}
